// 🎯 主执行入口：s6-runner.js
// 该文件负责加载各个策略，遍历历史数据并进行预测，支持不同窗口大小的动态调整

const _ = require("lodash");
const { readAllValues } = require("../../../awakened-potential/helpers/readAllValues.js");
const select32ByS1 = require("./select32ByS1");
const select32ByS2 = require("./select32ByS2");
const select32ByS3 = require("./select32ByS3");
const { select32ByS4, updateConsecutiveMiss } = require("./select32ByS4");
const select32ByS5 = require("./select32ByS5");

// 📦 读取历史开奖数据
const allValues = readAllValues("m"); // 假设数据读取函数，根据实际情况调整

// 📦 其他常量
let missCountMap = {}; // 记录每个号码的连续不中次数
const useWindow = true; // 是否启用滑动窗口

// 📦 用于统计最大连续错误次数
let maxWrongStreak = 0;  // 最大连续错误次数
let currentStreak = 0;    // 当前连续错误次数

// 📦 用于存储各个 windowSize 的结果
const results = [];

// 📦 主预测函数
function predict(windowSize) {
  let predictions = [];

  for (let i = windowSize; i < allValues.length; i++) {
    const temp = useWindow
      ? allValues.slice(i - windowSize, i)
      : allValues.slice(0, i);

    const currentNumber = allValues[i].number.toString().padStart(2, '0');

    // 策略 1：频率统计
    const resultS1 = select32ByS1(temp);

    // 策略 2：热冷号分析
    const resultS2 = select32ByS2(temp);

    // 策略 3：马尔科夫转移
    const resultS3 = select32ByS3(temp);

    // 策略 4：连错淘汰
    const resultS4 = select32ByS4(temp, missCountMap);

    // 融合策略结果
    const finalNumbers = select32ByS5([resultS1, resultS2, resultS3, resultS4]);

    // 更新连续不中次数
    missCountMap = updateConsecutiveMiss(missCountMap, finalNumbers, currentNumber);

    // 记录当前期的预测结果与实际结果对比
    const hit = finalNumbers.includes(currentNumber);
    predictions.push({ index: i, predict: finalNumbers, answer: currentNumber, hit });

    // 如果不中，增加当前连续错误次数
    if (!hit) {
      currentStreak++;
      maxWrongStreak = Math.max(maxWrongStreak, currentStreak);
    } else {
      currentStreak = 0;  // 如果命中，重置连续错误次数
    }
  }

  return predictions;
}

// 📦 循环不同 windowSize 测试
for (let windowSize = 5; windowSize <= 300; windowSize++) {
  console.log(`\n\n测试：windowSize = ${windowSize}`);
  
  // 执行预测
  const result = predict(windowSize);

  // 📦 输出结果
  const total = result.length;
  const correct = result.filter(item => item.hit).length;
  const accuracy = total > 0 ? ((correct / total) * 100).toFixed(2) : 0;

  results.push({
    windowSize,
    accuracy: parseFloat(accuracy),
    maxWrongStreak
  });
}

// ✅ 找出最大准确率和最小连续错误次数
const bestAccuracyResult = _.maxBy(results, 'accuracy');
const bestAccuracyWindow = bestAccuracyResult.windowSize;
const bestAccuracyValue = bestAccuracyResult.accuracy;
const bestAccuracyMaxStreak = bestAccuracyResult.maxWrongStreak;

const bestMinStreakResult = _.minBy(results, 'maxWrongStreak');
const bestMinStreakWindow = bestMinStreakResult.windowSize;
const bestMinStreakValue = bestMinStreakResult.maxWrongStreak;
const bestMinStreakAccuracy = bestMinStreakResult.accuracy;

console.log(`\n\n最佳窗口大小（最大准确率）: windowSize = ${bestAccuracyWindow}, 准确率 = ${bestAccuracyValue}%, 最大连续错误次数 = ${bestAccuracyMaxStreak}`);
console.log(`最佳窗口大小（最小连续错误次数）: windowSize = ${bestMinStreakWindow}, 最大连续错误次数 = ${bestMinStreakValue}, 准确率 = ${bestMinStreakAccuracy}%`);
